Android aidl流程简单分析

我们通过写一个从服务端(另外一个进程)获取用户名和密码作为demo来进行源码讲解。

  1. new一个IUserAidl.aidl

1
2
3
4
5
6

interface IUserAidl {
//注意 String S大写
String getUserName();
String getPwd();
}
  1. make生成IUserAidl.java文件
  2. 写一个service作为服务端

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27


    /**
    * Des:
    * Created by zzw on 2018/1/26.
    */

    public class MessageService extends Service {
    @Nullable
    @Override
    public IBinder onBind(Intent intent) {
    return new UserBinder();
    }

    private final class UserBinder extends IUserAidl.Stub {

    @Override
    public String getUserName() throws RemoteException {
    return "zzw";
    }

    @Override
    public String getPwd() throws RemoteException {
    return "123456";
    }
    }
    }
  3. AndroidManifest.xml注册service

    1
    2
    3
    <service
    android:process=":test"
    android:name=".MessageService"/>
  4. Activity绑定

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
     public class MainActivity extends AppCompatActivity {

    //客户端获取的aidl实例 , 通过这个实例就可以进行通讯
    private IUserAidl mIUserAidl;

    private ServiceConnection mServiceConnection = new ServiceConnection() {
    @Override
    public void onServiceConnected(ComponentName name, IBinder service) {
    //连接
    mIUserAidl = IUserAidl.Stub.asInterface(service);
    Log.e("zzz", "连接成功");
    }

    @Override
    public void onServiceDisconnected(ComponentName name) {
    //断开连接
    Log.e("zzz", "断开连接");
    }
    };

    @Override
    protected void onCreate(Bundle savedInstanceState) {
    super.onCreate(savedInstanceState);
    setContentView(R.layout.activity_main);
    //启动服务
    Intent intent = new Intent(this, MessageService.class);
    bindService(intent, mServiceConnection, Context.BIND_AUTO_CREATE);
    }



    public void getUserName(View view) {
    try {
    if (mIUserAidl != null) {
    String userName = mIUserAidl.getUserName();
    Log.e("zzz", userName);
    }
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }

    public void getPwd(View view) {
    try {
    if (mIUserAidl != null) {
    String pwd = mIUserAidl.getPwd();
    Log.e("zzz", pwd);
    }
    } catch (RemoteException e) {
    e.printStackTrace();
    }
    }

    @Override
    protected void onDestroy() {
    super.onDestroy();
    unbindService(mServiceConnection);
    }
    }

启动应用,发现是有test进程的 ,说明没问题。在当前客户端的进程(Acticity)可以发现是打印连接成功,然后依次点击获取用户名和密码,都对应打印成功,说明程序正常。我们接下来就开始分析源码,看看是怎么通讯的。

IUserAidl.java

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
public interface IUserAidl extends android.os.IInterface {
/**
* Local-side IPC implementation stub class.
*/
public static abstract class Stub extends android.os.Binder implements com.zzw.testaidl.IUserAidl {
private static final java.lang.String DESCRIPTOR = "com.zzw.testaidl.IUserAidl";

/**
* Construct the stub at attach it to the interface.
*/
public Stub() {
this.attachInterface(this, DESCRIPTOR);
}

/**
* Cast an IBinder object into an com.zzw.testaidl.IUserAidl interface,
* generating a proxy if needed.
*/
public static com.zzw.testaidl.IUserAidl asInterface(android.os.IBinder obj) {
if ((obj == null)) {
return null;
}
android.os.IInterface iin = obj.queryLocalInterface(DESCRIPTOR);
if (((iin != null) && (iin instanceof com.zzw.testaidl.IUserAidl))) {
return ((com.zzw.testaidl.IUserAidl) iin);
}
return new com.zzw.testaidl.IUserAidl.Stub.Proxy(obj);
}

@Override
public android.os.IBinder asBinder() {
return this;
}

@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws
android.os.RemoteException {
switch (code) {
case INTERFACE_TRANSACTION: {
reply.writeString(DESCRIPTOR);
return true;
}
case TRANSACTION_getUserName: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getUserName();
reply.writeNoException();
reply.writeString(_result);
return true;
}
case TRANSACTION_getPwd: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getPwd();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
return super.onTransact(code, data, reply, flags);
}

private static class Proxy implements com.zzw.testaidl.IUserAidl {
private android.os.IBinder mRemote;

Proxy(android.os.IBinder remote) {
mRemote = remote;
}

@Override
public android.os.IBinder asBinder() {
return mRemote;
}

public java.lang.String getInterfaceDescriptor() {
return DESCRIPTOR;
}

@Override
public java.lang.String getUserName() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getUserName, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}

@Override
public java.lang.String getPwd() throws android.os.RemoteException {
android.os.Parcel _data = android.os.Parcel.obtain();
android.os.Parcel _reply = android.os.Parcel.obtain();
java.lang.String _result;
try {
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getPwd, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();
} finally {
_reply.recycle();
_data.recycle();
}
return _result;
}
}

static final int TRANSACTION_getUserName = (android.os.IBinder.FIRST_CALL_TRANSACTION + 0);
static final int TRANSACTION_getPwd = (android.os.IBinder.FIRST_CALL_TRANSACTION + 1);
}

public java.lang.String getUserName() throws android.os.RemoteException;

public java.lang.String getPwd() throws android.os.RemoteException;
}

从上面这些代码我们可以知道,当客户端(Activity)和服务端(Service)bind的时候,服务端会把IUserAidl.Stub当做IBinder给传过来,然后通过IUserAidl.Stub.asInterface(service);拿到真正的IUserAidl实现类IUserAidl.Stub.Proxy
我们进入IUserAidl.Stub.Proxy这个类中,从调用的函数(getUserName getPwd)点进去查看是怎么进行通讯的。

1
2
3
4
5
6
Proxy关键代码:
//mRemote是服务端返回的IBinder实例 IUserAidl.Stub
_data.writeInterfaceToken(DESCRIPTOR);
mRemote.transact(Stub.TRANSACTION_getUserName, _data, _reply, 0);
_reply.readException();
_result = _reply.readString();

看到实际是调用了IUserAidl.Stubtransact函数,但是在IUserAidl.Stub中并没有transact函数,只有一个onTransact函数,这里我们可以猜测应该是调用transact的时候调用了onTransact函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
Stub.onTransact关键代码
@Override
public boolean onTransact(int code, android.os.Parcel data, android.os.Parcel reply, int flags) throws
android.os.RemoteException {
switch (code) {
case TRANSACTION_getUserName: {
data.enforceInterface(DESCRIPTOR);
java.lang.String _result = this.getUserName();
reply.writeNoException();
reply.writeString(_result);
return true;
}
}
}

首先通过code判断调用的是那个函数,然后在调用服务端的getUserName()函数拿到对应的值,在写入reply里面,然后在Proxy里面通过_reply读取出来,这样就完成了数据传递。

我们来验证我们的想法是不是在transact调用了onTransact。我们知道mRemoteIUserAidl.Stub,他是继承Binder的,在Binder查看到transact函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

/**
* Default implementation rewinds the parcels and calls onTransact. On
* the remote side, transact calls into the binder to do the IPC.
*/
public final boolean transact(int code, Parcel data, Parcel reply,
int flags) throws RemoteException {
if (false) Log.v("Binder", "Transact: " + code + " to " + this);

if (data != null) {
data.setDataPosition(0);
}
boolean r = onTransact(code, data, reply, flags);
if (reply != null) {
reply.setDataPosition(0);
}
return r;
}

我们从这段代码就可以看到确实是在transact中调用了onTransact函数。

总结:

  1. 客户端通过bind拿到服务端IBinder对象xxxx.Stub,然后通过xxxx.Stub.asInterface函数拿到对应的服务端通讯的代理类xxxx.Stub.Proxy
  2. 每个通讯的函数和都会生成一个code,当我们客户端调用函数时都会通过服务端xxxx.Stub对象调用transact函数,并将相应的code Parcel对象传入,然后回调onTransact函数,通过code判断调用服务端的对应的函数,拿到对应的数据将之写入Parcel里面
  3. 服务端调用完毕之后,客户端通过Parcel拿到对应的数据,然后返回即可。
-------------The End-------------